﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ComLib.ComType;
using LogLib;
using Newtonsoft.Json;
using System.Diagnostics;
using ComLib.ConfigService;
using ProcessConfig;
using ProcessConfig.ConfigType;
using KAImage.Config;
using DetectProcessing;
using System.Threading.Tasks;

namespace KProcessor
{
    public class PhotoDetecting : IDisposable
    {
        private Stopwatch _sw = new Stopwatch();

        private int takenIndex = 0;

        protected ApplyTo _apply = ApplyTo.ExitAndEntry;
        public ApplyTo ApplyType
        {
            get
            {
                return _apply;
            }
            set
            {
                _apply = value;
            }
        }

        protected PhotoApplyOption _applyOption = new PhotoApplyOption();
        public PhotoApplyOption ApplyOption
        {
            get
            {
                return _applyOption;
            }
            set
            {
                _applyOption = value;
            }
        }

        /// <summary>
        /// 指示当前的流程步骤阶段
        /// </summary>
        private DetectProcessMethods _method = DetectProcessMethods.DetectFront;
        public DetectProcessMethods ProcessMethod
        {
            get { return _method; }
        }

        /// <summary>
        ///  识别和检测处理对象
        /// </summary>
        private Dictionary<ApplyTo, DetectProcess> DicProcess = new Dictionary<ApplyTo,DetectProcess>();

        /// <summary>
        /// 获取当前执行综合及检测处理的对象
        /// </summary>
        public DetectProcess Process
        {
            get
            {
                
                Log.WriteAsync("获取Process对象:" + _apply.ToString());
                _applyOption.ApplyType = _apply;
                if (!DicProcess.ContainsKey(_apply))
                {
                    DicProcess.Add(_apply, new DetectProcess(_applyOption));
                    Log.WriteAsync("2DicProcess.Add:" + _apply.ToString() + "," + _applyOption.PxlFltPath);
                }
                return DicProcess[_apply];
            }
        }

        /// <summary>
        /// 脸部光线强度评价值
        /// </summary>
        private float _detectFaceLight = 0F;

        //文件名
        private string _fileName = "";
        public string FileName
        {
            get { return _fileName; }
            set { _fileName = value; }
        }

        private PhotoErrorCounter _errorCounter = null;
        public PhotoErrorCounter ErrorCounter
        {
            get { return _errorCounter; }
        }

        protected string _error = "";
        public string ErrorMessage
        {
            get
            {
                return _error;
            }
        }

        private DetectRequestArgs RequestArgs = null;

        public event Action AppExited;
        public void OnAppExited(string inParams)
        {
            if (AppExited != null)
            {
                AppExited();
            }
        }

        public PhotoDetecting()
        {
            Log.WriteAsync("实例化PhotoDetecting");
            if (Configs.NoSupportAdvice.Enabled)
            {
                _errorCounter = new PhotoErrorCounter();
            }
            _applyOption = Configs.PhoApplyOption;
            SetProcessHandle(_applyOption.ApplyType);
            Log.WriteAsync("SetProcessHandle:" + Configs.PhoApplyOption.PxlFltPath);
        }

        private void SetProcessHandle(ApplyTo apply)
        {
            _applyOption.ApplyType = apply;
            _apply = apply;
            if (!DicProcess.ContainsKey(_apply))
            {
                DicProcess.Add(_apply, new DetectProcess(new PhotoApplyOption(_applyOption)));
            }
        }

        private bool ParseRequsetArgs(string inputingString)
        {
            try
            {
                Log.WriteAsync("收到请求: " + inputingString);
                RequestArgs = JsonConvert.DeserializeObject<DetectRequestArgs>(inputingString);
                Log.WriteAsync("解析成功!");
                return true;
            }
            catch (Exception ex)
            {
                _error = "输入参数无效，解析失败：" + ex.Message;
                Log.WriteExceptionAsync(ex.ToString());
                Log.WriteAsync(_error);
                return false;
            }
        }

        public string OnHandling(string inputString)
        {
            string outData = "";
            Task t = Task.Run(async () =>
            {
                _error = "";
                if (!ParseRequsetArgs(inputString))
                {
                    DetectResultArgs outtingArgs = new DetectResultArgs();
                    outtingArgs.Success = false;
                    outtingArgs.ErrorMessage = _error;
                    outData = JsonConvert.SerializeObject(outtingArgs);
                    return;
                }
                if (RequestArgs == null)
                {
                    _error = "输入参数无效，解析结果为空.";
                    DetectResultArgs outtingArgs = new DetectResultArgs();
                    outtingArgs.Success = false;
                    outtingArgs.ErrorMessage = _error;
                    outData = JsonConvert.SerializeObject(outtingArgs);
                    return;
                }

                // 当收到消息需要关闭应用程序时
                if (RequestArgs.Method == DetectProcessMethods.ExitApp)
                {
                    _error = "Exit";
                    DetectResultArgs outtingArgs = new DetectResultArgs();
                    outtingArgs.Success = false;
                    outtingArgs.ErrorMessage = _error;
                    OnAppExited("");
                    outData = JsonConvert.SerializeObject(outtingArgs);
                    return;
                }

                // 当文件保存名称不同时
                // 说明不是同一个对象（人）的拍照流程
                // 此时需要重新设置一些参数
                if (!string.IsNullOrEmpty(_fileName) && !RequestArgs.PhotoName.Equals(_fileName))
                {
                    if (_errorCounter != null)
                    {
                        _errorCounter.Reset();
                    }
                }
                Log.WriteAsync($"设置照片制证类型为:{RequestArgs.App}.");
                SetProcessHandle(RequestArgs.App);
                _fileName = RequestArgs.PhotoName;
                _method = RequestArgs.Method;
                takenIndex = RequestArgs.Index;
             
                RecogIn inRec = null;
                // 从共享内存中获取捕获的照片数据
                Log.WriteAsync($"从共享内存中获取捕获的照片数据开始.");
                if (!TakePhotoFromShareMemory(out inRec))
                {
                    DetectResultArgs outtingArgs = new DetectResultArgs();
                    outtingArgs.Success = false;
                    outtingArgs.ErrorMessage = _error;
                    outData = JsonConvert.SerializeObject(outtingArgs);
                    return;
                }
                Log.WriteAsync($"从共享内存中获取捕获的照片数据结束");
                //Log.WriteAsync($"开始调节照片...");
                //if (_method == DetectProcessMethods.DetectAndTake && KAConfigs.AlgorApplying.Enabled)
                //{
                //    inRec.ReturnBuffer();
                //    inRec.AdjustImage();
                //}
                //Log.WriteAsync($"调节照片结束");
                try
                {
                    RecogOut detResult = new RecogOut();
                    _sw.Restart();
                    Log.WriteAsync("开始处理照片:" + _method.ToString() + "," + _apply.ToString() + "," + _applyOption.PxlFltPath);
                    switch (_method)
                    {
                        case DetectProcessMethods.DetectFront:
                            Process.HandlePrimary(inRec, detResult);
                            break;
                        case DetectProcessMethods.Detect:
                            await Process.Handle(inRec, detResult, -1);
                            break;
                        case DetectProcessMethods.DetectAndTake:
                            await Process.Handle(inRec, detResult, takenIndex);
                            break;
                        default:
                            break;
                    }
                    _sw.Stop();
                    inRec.ReturnBuffer();
                    inRec.ReleaseMemoryStream();
                    detResult.ElapsedMilliseconds = _sw.ElapsedMilliseconds;
                    outData = ProcessDetectResult(detResult);
                    Log.WriteAsync($"照片处理完成， 返回: {outData}");
                    return;
                }
                catch (Exception ex)
                {
                    _error = "检测过程发生了异常:" + ex.Message;
                    Log.WriteExceptionAsync(ex.ToString());
                    DetectResultArgs outtingArgs = new DetectResultArgs();
                    outtingArgs.Success = false;
                    outtingArgs.ErrorMessage = _error;
                    outData = JsonConvert.SerializeObject(outtingArgs);
                    return;
                }
            });
            t.Wait();
            return outData;
        }

        private bool TakePhotoFromShareMemory(out RecogIn inRec)
        {
            inRec = new RecogIn(_fileName);
            SourceReceiver receiver = new SourceReceiver();
            bool bRet = receiver.TakePhotoFromShareMemory();
            if (bRet)
            {
                inRec.SetBufferData(receiver.NewFrameBuffer, receiver.ReadDataLength);
            }
            else
            {
                _error = receiver.ErrorMessage;
                Log.WriteAsync("获取最新的一帧数据失败: " + receiver.ErrorMessage);
            }
            return bRet;
        }

        private bool TakePhotoFromClipboard(out RecogIn inRec)
        {
            inRec = new RecogIn(_fileName);
            SourceReceiver receiver = new SourceReceiver();
            bool bRet = receiver.TakePhotoFromClipboard();
            if (bRet)
            {
                inRec.SetBufferData(receiver.NewFrameBuffer, receiver.ReadDataLength);
            }
            else
            {
                _error = receiver.ErrorMessage;
                Log.WriteAsync("获取剪切板数据失败: " + receiver.ErrorMessage);
            }
            return bRet;
        }

        /// <summary>
        /// 所有检测项通过
        /// </summary>
        private void OnDetectPass()
        {
            takenIndex++;
        }

        /// <summary>
        /// 监测顽固性错误
        /// </summary>
        /// <param name="detResult"></param>
        private void WatchAlwaysError(RecogOut detResult)
        {
            string key = detResult.Correction.Tips;
            _errorCounter.AddKey(key);
            if (_errorCounter.IsOverRangle(Configs.NoSupportAdvice.ErrorActivationTimes, key))
            {
                detResult.NeverPassReason = key;
                detResult.NeverPass = true;
            }
        }

        /// <summary>
        /// 处理检测结果
        /// </summary>
        private string ProcessDetectResult(RecogOut detResult)
        {
            DetectResultArgs outtingArgs = new DetectResultArgs();
            outtingArgs.Method = _method;
            outtingArgs.App = _apply;
            outtingArgs.Index = takenIndex;
            outtingArgs.Success = true;
            PassElements elem = detResult.PassElems;
            if (!elem.FaceEye)
            {
                detResult.PassElems.DetectPassed = false;
                outtingArgs.Result = detResult;
                return JsonConvert.SerializeObject(outtingArgs);
            }
            outtingArgs.SourceFileName = detResult.SourceImagePath;
            outtingArgs.DestFileName = detResult.DestImagePath;
            if (!elem.PxlQcPass)
            {
                detResult.PassElems.DetectPassed = false;
                if (Configs.NoSupportAdvice.Enabled)
                {
                    WatchAlwaysError(detResult);
                }              
                outtingArgs.Result = detResult;
                return JsonConvert.SerializeObject(outtingArgs);
            }

            if (Process.DoQCCheck)
            {
                if (!elem.QcDllCheck)
                {
                    detResult.PassElems.DetectPassed = false;
                    if (Configs.NoSupportAdvice.Enabled)
                    {
                        WatchAlwaysError(detResult);
                    }      
                    outtingArgs.Result = detResult;
                    return JsonConvert.SerializeObject(outtingArgs);
                }
            }
            _detectFaceLight = detResult.Processing.SrcLAB.L;
            detResult.PassElems.DetectPassed = true;
            outtingArgs.Result = detResult;
            return JsonConvert.SerializeObject(outtingArgs);
        }

        public void Dispose()
        {
            foreach (KeyValuePair<ApplyTo, DetectProcess> p in DicProcess)
            {
                DetectProcess pro = p.Value;
                pro.Dispose();
            }
            DicProcess.Clear();
        }
    }
}
 //private void ReportToMainForm(RecogIn inRec, RecogOut result)
 //       {
 //           if (takenIndex >= Configs.TakingOption.TakingCount)
 //           {
 //               return;
 //           }
 //           TakenPhoto item = null;
 //           if (result.PassElems.DetectPassed && result.Processing.bBeginShoot)
 //           {
 //               if (File.Exists(result.DestImagePath))
 //               {
 //                   Bitmap passImage = new Bitmap(result.DestImagePath);
 //                   item = new TakenPhoto(takenIndex, inRec.SourceImage, passImage);
 //                   item.SourcePath = result.SourceImagePath;
 //                   item.DestImagePath = result.DestImagePath;
 //                   passImage.Dispose();
 //                   passImage = null;
 //               }
 //           }
 //           DetectResultReportedEventArgs e = new DetectResultReportedEventArgs(item, result);
 //           OnDetectResultReported(e);
 //       }